package ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.imp;

import java.util.Date;

import net.wimpi.modbus.procimg.DigitalIn;
import net.wimpi.modbus.procimg.DigitalOut;
import net.wimpi.modbus.procimg.InputRegister;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.devicecontroller.ProcessImageDated;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.AddressType;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.Device;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.Field;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.FieldService;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.DeviceDAO;

public class FieldServiceImp implements FieldService {
	
	public static final Integer INT_0 = new Integer(0);
	public static final Integer INT_1 = new Integer(1); 
	
	//TODO: Completo
	private Field field;
	private DeviceDAO deviceDAO;
	private Device device;
	private ProcessImageDated image;
	
	@Override
	public String getName() {
		return field.getName();
	}

	@Override
	public Integer getValue() {
		Integer last;
		
		switch (field.getAddressType()){
		
			case COIL:
				
				DigitalOut valueCoil = image.getDigitalOut(field.getAddress());
				
				if(valueCoil == null)
					return null;
				
				if(valueCoil.isSet())
					last = INT_1;
				else
					last = INT_0;
				
				break;
			
			case DISCRETE:
				
				DigitalIn valueDiscrete = image.getDigitalIn(field.getAddress());
				
				if(valueDiscrete == null)
					return null;
				
				if(valueDiscrete.isSet())
					last = INT_1;
				else
					last = INT_0;
				
				break;
			
			case HOLDING_REGISTER:
				
				InputRegister valueRegister = image.getRegister(field.getAddress());
				
				if(valueRegister == null)
					return null;
				
				last = valueRegister.getValue();
				
				break;
				
			case INPUT_REGISTER:
				
				InputRegister valueInputRegister = image.getInputRegister(field.getAddress());
				
				if(valueInputRegister == null)
					return null;
				
				last = valueInputRegister.getValue();
				
				break;
				
			default:
				return null;
		}
		
		last = decodeValue(last);
		return last;
	}

	private Integer decodeValue(Integer last) {
		
		AddressType type = field.getAddressType();
		
		boolean isRegistry = ( type == AddressType.HOLDING_REGISTER || 
							   type == AddressType.INPUT_REGISTER );
		
		boolean isBitField = field.getBitType(); 
		
		if(isBitField && isRegistry ){
			
			int offset = field.getBitOffset();
			
			int bitMask = 0x0001 << offset;
			
			last = ( ( last & bitMask ) == 0 ? INT_0 : INT_1 );
		
		}
		
		return last;
	}

	@Override
	public Date getLastDate() {
		
		int ref = field.getAddress();
		
		switch(field.getAddressType()){
		
			case COIL:
				return image.getDigitalOutDate(ref);
				
			case DISCRETE:
				return image.getDigitalInDate(ref);
				
			case HOLDING_REGISTER:
				return image.getRegisterDate(ref);
				
			case INPUT_REGISTER:
				return image.getInputRegisterDate(ref);
				
			default:
				return null;
				
		}
		
	}


	/**
	 * @return the field
	 */
	public Field getField() {
		return field;
	}

	/**
	 * @param field the field to set
	 */
	public void setField(Field field) {
		this.field = field;
	}

	/**
	 * @return the devicedao
	 */
	public DeviceDAO getDeviceDAO() {
		return deviceDAO;
	}

	/**
	 * @param devicedao the devicedao to set
	 */
	public void setDeviceDAO(DeviceDAO deviceDAO) {
		this.deviceDAO = deviceDAO;
	}

	/**
	 * @return the device
	 */
	public Device getDevice() {
		return device;
	}

	/**
	 * @param device the device to set
	 */
	public void setDevice(Device device) {
		this.device = device;
	}

	@Override
	public Integer getID() {
		return field.getID();
	}

	@Override
	public String getDeviceName() {
		return device.getName();
	}

	public ProcessImageDated getImage() {
		return image;
	}

	public void setImage(ProcessImageDated image) {
		this.image = image;
	}

}
